using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using MacomberMap.Common.Internals;
using MacomberMap.Common.Components;
using MacomberMap.Common.Database_Interface.CIM.Components;
using MacomberMap.Common.Database_Interface.CIM;

namespace MacomberMap.Common.Database_Interface.CIM.User_Interfaces
{
    /// <summary>
    /// This class allows for selection of a CIM element
    /// </summary>
    public partial class CIM_Element_Locator : UserControl
    {
        #region Event handling
        /// <summary>
        /// Our collection of selected elements
        /// </summary>
        private List<CIM_Element> SelectedElements = new List<CIM_Element>(30);

        /// <summary>
        /// Indicate that an element has been selected
        /// </summary>
        /// <param name="SelectedElement">The selected element</param>
        public delegate void ElementSelectedDelegate(CIM_Element SelectedElement);

        /// <summary>
        /// An element has been selected
        /// </summary>
        public event ElementSelectedDelegate ElementSelected;

        /// <summary>
        /// Our collection of substation to element mappings
        /// </summary>
        private Dictionary<String, CIM_Element> Subs;

        /// <summary>
        /// Our collection of contingency definitions
        /// </summary>
        private Dictionary<String, CIM_Element> Ctgs;
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize the CIM locator
        /// </summary>
        public CIM_Element_Locator()
        {
           
            try
            {
                InitializeComponent();
                //Assign all CIM types to our combo box
                if (MM_Database_CIM.Types != null)
                {
                    foreach (KeyValuePair<String, Int32> CIMType in MM_Database_CIM.Types)
                        cmbElementType.Items.Add(CIMType.Key);
                    Subs = new Dictionary<string, CIM_Element>(MM_Database_CIM.ElementsOfType("cim:Substation").Count);
                    foreach (CIM_Element Substation in MM_Database_CIM.ElementsOfType("cim:Substation"))
                    {
                        String SubName = MM_Repository.TitleCase(Substation.Name);
                        Subs.Add(SubName, Substation);
                        cmbSubstations.Items.Add(SubName);
                    }

                    Ctgs = new Dictionary<string, CIM_Element>(MM_Database_CIM.ElementsOfType("cim:Contingency").Count);
                    foreach (CIM_Element Ctg in MM_Database_CIM.ElementsOfType("cim:Contingency"))
                    {
                        String CtgName = MM_Repository.TitleCase(Ctg.Name);
                        Ctgs.Add(CtgName, Ctg);
                        cmbContingencies.Items.Add(CtgName);
                    }
                }
                cmbElementType.Sorted = true;
                cmbSubstations.Sorted = true;
                cmbContingencies.Sorted = true;
            }
            catch (Exception ex) {
                MessageBox.Show("Error: " + ex.Message);
            }
        }
        #endregion

        #region User interactions
        /// <summary>
        /// When the type changes, update accordingly.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpdateRDFByIndex(object sender, EventArgs e)
        {
            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");
            foreach (CIM_Element Elem in MM_Database_CIM.ElementsOfType(cmbElementType.Text))
                dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name)].Tag = Elem;

        }

        /// <summary>
        /// Locate the requested rdf:ID
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtRdfID_KeyPress(object sender, KeyPressEventArgs e)
        {
           

            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");
            
            CIM_Element Elem = null;
            MM_Database_CIM.Elements.TryGetValue(new MM_rdfID(txtRdfID.Text), out Elem);
            if (Elem != null)
                dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name)].Tag = Elem;
        }

        private void txtTEID_KeyPress(object sender, KeyPressEventArgs e)
        {
           
            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");

            UInt64 TEID;
            CIM_Element Elem = null;
            if (UInt64.TryParse(txtTEID.Text, out TEID))
            {
                MM_Database_CIM.TEIDs.TryGetValue(TEID, out Elem);
                dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name)].Tag = Elem;
            }
        }

        /// <summary>
        /// Update only elements within the selected substation
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbSubstations_SelectedIndexChanged(object sender, EventArgs e)
        {
            
            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");
            dgvElements.Columns.Add("Type", "Type");
            dgvElements.Columns.Add("TEID", "TEID");
            if (cmbSubstations.SelectedItem == null)
                return;
            foreach (CIM_Element Elem in Subs[(string)cmbSubstations.SelectedItem].Elements)            
                dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name, Elem.Type.Split(':')[1], Elem.TEID)].Tag = Elem;
            //foreach (CIM_Element Elem in Subs[(string)cmbSubstations.SelectedItem].Nodes)
            //    dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name, Elem.Type.Split(':')[1], Elem.TEID)].Tag = Elem;
        }

        /// <summary>
        /// Update only elements within the selected contingency definition
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbContingencies_SelectedIndexChanged(object sender, EventArgs e)
        {
            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");
            dgvElements.Columns.Add("Type", "Type");
            dgvElements.Columns.Add("TEID", "TEID");
            if (cmbContingencies.SelectedItem == null)
                return;
            foreach (CIM_Element Elem in Ctgs[(string)cmbContingencies.SelectedItem].Elements)                
                dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name, Elem.Type.Split(':')[1], Elem.TEID)].Tag = Elem;
        }


        /// <summary>
        /// Add an attribute in to the data grid view
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OutItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            String AttributeType = e.ClickedItem.Tag as string;

            DataGridViewColumn NewCol = dgvElements.Columns[dgvElements.Columns.Add(AttributeType, AttributeType.Split('.')[1])];
            NewCol.ToolTipText = AttributeType;



            foreach (DataGridViewRow dgr in dgvElements.Rows)
                if (dgr.Tag is CIM_Element)
                    dgr.Cells[AttributeType].Value = (dgr.Tag as CIM_Element)[AttributeType];

            (sender as ToolStripDropDownItem).Owner.Hide();
        }

       

        /// <summary>
        /// Handle the user's double clicking by returning the selected element
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvElements_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (ElementSelected != null && e.RowIndex > -1)
                
                ElementSelected(dgvElements.Rows[e.RowIndex].Tag as CIM_Element);
        }

        /// <summary>
        /// Handle the right-click on the elements view, allowing for different types to be added in.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvElements_MouseClick(object sender, MouseEventArgs e)
        {
            //If we have a right-click button, pop up a menu of all possible attribute types
            if (e.Button == MouseButtons.Right)
            {
                List<Byte> SeenTypes = new List<byte>();
                SortedDictionary<String, bool> Attributes = new SortedDictionary<string, bool>();
                foreach (DataGridViewRow dgr in dgvElements.Rows)
                    if (dgr.Tag is CIM_Element && !SeenTypes.Contains((dgr.Tag as CIM_Element).TypeByte))
                    {
                        foreach (int Attr in MM_Database_CIM.AttributesByType[(dgr.Tag as CIM_Element).TypeByte])
                            if (!Attributes.ContainsKey(MM_Database_CIM.Attributes.GetKeyAt(Attr)))
                                Attributes.Add(MM_Database_CIM.Attributes.GetKeyAt(Attr), true);
                        SeenTypes.Add((dgr.Tag as CIM_Element).TypeByte);
                    }

                //Now, build out our menu
                ContextMenuStrip cms = new ContextMenuStrip();
                foreach (String str in Attributes.Keys)
                {
                    String[] splStr = str.Split(new char[] { '.' }, 2);
                    ToolStripMenuItem OutItem;
                    if (cms.Items.ContainsKey(splStr[0]))
                        OutItem = cms.Items[splStr[0]] as ToolStripMenuItem;
                    else
                    {
                        OutItem = cms.Items.Add(splStr[0]) as ToolStripMenuItem;
                        OutItem.Name = splStr[0];
                        OutItem.DropDownItemClicked += new ToolStripItemClickedEventHandler(OutItem_DropDownItemClicked);
                    }
                    (OutItem.DropDownItems.Add(splStr[1]) as ToolStripItem).Tag = str;
                }
                cms.Show(sender as Control, e.Location);

            }
        }
        #endregion        

        #region Drag/drop handling
        /// <summary>
        /// Allow the user to drag/drop a CIM element out of the window
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvElements_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && SelectedElements.Count > 0 && !dgvElements.Bounds.Contains(e.Location))
                dgvElements.DoDragDrop(SelectedElements.ToArray(), DragDropEffects.All);
        }

        /// <summary>
        /// Update our list of selected elements for potential drag/drop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvElements_SelectionChanged(object sender, EventArgs e)
        {
            SelectedElements.Clear();
            foreach (DataGridViewCell Cell in dgvElements.SelectedCells)
                if (!SelectedElements.Contains(dgvElements.Rows[Cell.RowIndex].Tag as CIM_Element))
                    SelectedElements.Add(dgvElements.Rows[Cell.RowIndex].Tag as CIM_Element);
        }
        #endregion

        #region Unknown element propigation
        /// <summary>
        /// Write out only our list of unknown elements
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tabsType_Selected(object sender, TabControlEventArgs e)
        {
            if (e.TabPage == tabUnknowns)
            {

                dgvElements.Rows.Clear();
                dgvElements.Columns.Clear();
                dgvElements.Columns.Add("rdfID", "rdf:ID");
                dgvElements.Columns.Add("IncomingLinks", "Incoming Links");
                foreach (CIM_Element Elem in MM_Database_CIM.Elements.Values)
                    if (Elem.Start == -1)
                        dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem._InLinks.Count.ToString("#,##0"))].Tag = Elem;
            }
            else if (e.TabPage == tabCounts)
            {
                dgvElements.Rows.Clear();
                dgvElements.Columns.Clear();
                dgvElements.Columns.Add("prefix", "Prefix");
                dgvElements.Columns.Add("type", "Type");
                DataGridViewColumn dCount = dgvElements.Columns[dgvElements.Columns.Add("Count", "Count")];
                dCount.ValueType = typeof(int);
                dCount.DefaultCellStyle.Format = "#,##0";

                foreach (KeyValuePair<byte, List<CIM_Element>> kvp in MM_Database_CIM.ElementsByType)
                {
                    String[] ElemType = MM_Database_CIM.Types.GetKeyAt(kvp.Key).Split(':');
                    if (ElemType.Length == 1)
                        ElemType = new string[] { "", ElemType[0] };
                    dgvElements.Rows.Add(ElemType[0], ElemType[1], kvp.Value.Count);
                }
                dgvElements.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader;
            }
        }
        #endregion






    }
}
